home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / printing / print clipped offscreen / offscreen region.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  11.4 KB  |  400 lines

  1. /*
  2.     File:        Offscreen Region.c
  3.  
  4.     Contains:    Print clipped offscreen:  Takes a text string, turns it into a region and
  5.                 copies a clipped bitmap (just a pattern in this case, but it could be 
  6.                 anything) to the printing grafPort.  The effect is patterned text here, 
  7.                 but any image could be showing through the text.
  8.     
  9.                 You can also see the clipped image on the screen by turning on DrawStuffToScreen.
  10.                 Do this with qdToScreen below.
  11.  
  12.                 This sample is a rewrite of the 'Offscreen region MaskRgn' sample.
  13.  
  14.  
  15.     Written by: Tim Carroll and Ingrid Kelly    
  16.  
  17.     Copyright:    Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
  18.  
  19.                 You may incorporate this Apple sample source code into your program(s) without
  20.                 restriction. This Apple sample source code has been provided "AS IS" and the
  21.                 responsibility for its operation is yours. You are not permitted to redistribute
  22.                 this Apple sample source code as "Apple sample source code" after having made
  23.                 changes. If you're going to re-distribute the source, we require that you make
  24.                 it clear in the source that the code was descended from Apple sample source
  25.                 code, but that you've made changes.
  26.  
  27.     Change History (most recent first):
  28.                 7/26/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  29.                 11/96                        Rewritten as 'Print clipped offscreen' to fix 
  30.                                             problems printing to PostScript printers (changed
  31.                                             maskRgn to clipping the region before sending to the
  32.                                             printing port since PS printers don't support maskRgn)
  33.     
  34.                 
  35.  
  36. */
  37.  
  38. /*************************************************************************************
  39. #
  40. #    CONDITIONALS
  41. #
  42. #    There are a number of conditionals used to control exactly how the code runs.
  43. #
  44. #
  45. #    qDebugging  -- Whether or not additional debugging code should be inserted.  With this
  46. #   turned on, most errors will DebugStr almost immediately and return errors as the error
  47. #   propagates up the calling chain.  This is slower, but if you've found a weird bug,
  48. #   this is the fastest way to replicate it.
  49. #
  50. #    qdToScreen -- if this is set to 1, we draw to the screen instead of to the printer.
  51. #
  52. *************************************************************************************/
  53.  
  54. #define qDebugging 1
  55. #define qdToScreen 0
  56.  
  57.  
  58. /*********************************************************************************
  59. #    ERROR HANDLING MACROS
  60. #
  61. #    These macros can be used to implement nice error handling within a function.
  62. #    Essentially, all errors jump to an error handler at the end of the function, which
  63. #    should cleanup  any leftovers and return the appropriate error result.
  64. #
  65. #    Note that the error handlers take a message string.  This should be a good
  66. #    indication of the actual error, and it will appear when debugging is turned on.
  67. #
  68. #    Note that any additional sanity checking code can be added to any function by using
  69. #
  70.     
  71.     #if qDebugging
  72.           // do additional sanity checking here.
  73.     #endif
  74. #
  75. #    For example, this could be used to check the internal validity of an object before
  76. #    taking an action.
  77. #    
  78. *********************************************************************************/
  79.  
  80. #ifndef qDebugging
  81.     #define qDebugging 0
  82. #endif
  83.  
  84. #if qDebugging
  85.     #define SIGNAL_ERROR(msg)        {DebugStr(msg); goto error;}
  86. #else
  87.     #define SIGNAL_ERROR(msg)        {goto error;}
  88. #endif
  89.  
  90. #define FAIL_NIL(y,msg)            if (y == NULL) SIGNAL_ERROR(msg)
  91. #define FAIL_OSERR(y,msg)        if (y != noErr) SIGNAL_ERROR(msg)
  92. #define FAIL_FALSE(y,msg)        if (!y) SIGNAL_ERROR(msg)
  93.  
  94.  
  95.  
  96. #include <Printing.h>
  97. #include <QDOffscreen.h>
  98. #include <Fonts.h>
  99.  
  100.  
  101. void         main (void);
  102. OSStatus    PrintStuff (void);
  103. OSStatus    DrawStuff (Rect theWorld);
  104. OSStatus    PrepareOffScreens(void);
  105. OSStatus    KillOffscreens(void);
  106. OSStatus    DrawStuffToScreen(void);
  107.  
  108. /*------ globals --------------------------------------------------------------------------*/
  109.  
  110. GWorldPtr    gMaskOffscreen = NULL, gImageOffscreen = NULL;
  111. RgnHandle    gMaskRegion = NULL;
  112. Rect        gBoundsRect;
  113.  
  114. /*------ main ----------------------------------------------------------------------------*/
  115. //    All main does is the standard mac init, followed by initializing the offscreens
  116. //    and printing.
  117. /*----------------------------------------------------------------------------------------*/
  118.  
  119. void main(void)
  120. {
  121.     OSStatus theErr = noErr;
  122.     
  123.     InitGraf(&qd.thePort);
  124.     InitFonts();
  125.     InitWindows();
  126.     InitMenus();
  127.     TEInit();
  128.     InitDialogs(nil);
  129.     InitCursor();
  130.  
  131.     theErr = PrepareOffScreens();
  132.     FAIL_OSERR (theErr, "\pError: Failed to prepare the offscreen environment")
  133.     
  134.     #if qdToScreen        
  135.         DrawStuffToScreen();
  136.     while (!Button());
  137.     #else
  138.         PrintStuff ();
  139.     #endif
  140.     
  141. error:
  142.     theErr = KillOffscreens();
  143.     
  144. } /* main */
  145.  
  146.  
  147. /*------ PrepareOffScreens ---------------------------------------------------------------*/
  148. //    PrepareOffScreens sets up the GWorlds and does the actual text clipping.
  149. /*----------------------------------------------------------------------------------------*/
  150.  
  151. OSStatus PrepareOffScreens()
  152. {
  153.     OSStatus theErr = noErr;
  154.     CGrafPtr savePort;
  155.     GDHandle saveDevice;
  156.     short fontNum;
  157.     PixPatHandle image = NULL;
  158.     PixMapHandle thePix = NULL;
  159.     
  160.     SetRect(&gBoundsRect,0,0,700,700);
  161.     GetGWorld(&savePort,&saveDevice);
  162.     
  163.     /* Create the offscreen mask */
  164.     
  165.     theErr = NewGWorld(&gMaskOffscreen, 1, &gBoundsRect, NULL, NULL, 0);
  166.     FAIL_OSERR (theErr, "\pError: Failed to create mask GWorld")
  167.     FAIL_NIL (gMaskOffscreen, "\pError: Failed to create mask GWorld")
  168.     
  169.     thePix = GetGWorldPixMap (gMaskOffscreen);
  170.     FAIL_NIL (thePix, "\pError: Failed to retrieve mask pixmap")
  171.     FAIL_FALSE (LockPixels(thePix), "\pError: Failed to lock the mask pixmap")
  172.     
  173.     SetGWorld(gMaskOffscreen,NULL);
  174.     ClipRect(&gBoundsRect);
  175.     
  176.     ForeColor(blackColor);
  177.     EraseRect(&gBoundsRect);
  178.     GetFNum("\pTimes",&fontNum);
  179.     TextFont(fontNum);
  180.     TextFace(bold);
  181.     TextSize(60);
  182.     MoveTo(10,100);
  183.     DrawString("\pHere’s our string test");
  184.     
  185.     SetGWorld (savePort,saveDevice);
  186.     
  187.     /* OK, the mask pixmap now has our string in it.  Let's make a region from it. */
  188.  
  189.     gMaskRegion = NewRgn();
  190.     theErr = QDError();
  191.     FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
  192.     FAIL_NIL (gMaskRegion,"\pError: Failed to create the mask region")
  193.     
  194.     theErr = BitMapToRegion(gMaskRegion,&((GrafPtr)gMaskOffscreen)->portBits);
  195.     FAIL_OSERR (theErr, "\pError: Failed to convert the mask to a region")
  196.     
  197.     UnlockPixels (thePix);
  198.     
  199.     
  200.     /* Build the offscreen pixmap that we'll draw to the printer */
  201.     
  202.     theErr = NewGWorld(&gImageOffscreen, 8, &gBoundsRect, NULL, NULL, 0);
  203.     FAIL_OSERR (theErr, "\pError: Failed to create image GWorld")
  204.     FAIL_NIL (gImageOffscreen, "\pError: Failed to create image GWorld")
  205.     
  206.     thePix = GetGWorldPixMap (gImageOffscreen);
  207.     FAIL_NIL (thePix, "\pError: Failed to retrieve image pixmap")
  208.     FAIL_FALSE (LockPixels(thePix), "\pError: Failed to lock the image pixmap")
  209.     
  210.     /* We erase the image, then we use the mask clipping region and draw a color
  211.        pattern to the pixmap */ 
  212.     
  213.     image = GetPixPat(16);
  214.     FAIL_NIL (image, "\pError: Failed to load the pixel pat")
  215.     
  216.     SetGWorld(gImageOffscreen,NULL);
  217.     ClipRect (&gBoundsRect);
  218.     EraseRect (&gBoundsRect);
  219.     
  220.     SetClip(gMaskRegion);
  221.     
  222.     FillCRect(&gBoundsRect, image);
  223.     
  224.     // restore the clip rect
  225.     ClipRect (&gBoundsRect);
  226.     UnlockPixels(thePix);
  227.     
  228.     // Cleanup and return noErr;
  229.     goto cleanup;
  230.     
  231. error:
  232.     if (theErr == noErr)
  233.         theErr = paramErr;
  234.     
  235. cleanup:
  236.     SetGWorld (savePort, saveDevice);
  237.     if (image != NULL)
  238.         DisposePixPat(image);
  239.     
  240.     return theErr;
  241. }
  242.  
  243. /*------ DrawStuff -----------------------------------------------------------------------*/
  244. // DrawStuff CopyBits from the offscreen into the printer/window port.
  245. /*----------------------------------------------------------------------------------------*/
  246.  
  247. OSStatus DrawStuff (Rect theRect)
  248. {
  249.     #pragma unused(theRect)
  250.     OSStatus        theErr = noErr;
  251.     GrafPtr            currentPort;
  252.     PixMapHandle     offscreenPix;
  253.  
  254.     /* Here's where we use CopyBits to copy from gImageOffscreen to the printer/window port */
  255.     
  256.     GetPort(¤tPort);
  257.     
  258.     offscreenPix = GetGWorldPixMap(gImageOffscreen);
  259.     FAIL_NIL (offscreenPix, "\pError: Failed to retrieve image pixmap")
  260.     FAIL_FALSE (LockPixels(offscreenPix), "\pError: Failed to lock the image pixmap")
  261.  
  262.     CopyBits((BitMap*)*offscreenPix,
  263.              &(currentPort)->portBits,
  264.              &gBoundsRect, &gBoundsRect, srcCopy, NULL);
  265.              
  266.     UnlockPixels(offscreenPix);
  267.  
  268.     goto cleanup;
  269.     
  270. error:
  271.     if (theErr == noErr)
  272.         theErr = paramErr;
  273. cleanup:
  274.     return theErr;
  275. }  /* DrawStuff */
  276.  
  277. /*------ PrintStuff ----------------------------------------------------------------------*/
  278. // PrintStuff performs the generic printing calls for printing to the Macintosh Printing
  279. // Manager.
  280. // Sets the current port to the printer port.
  281. /*----------------------------------------------------------------------------------------*/
  282.  
  283. OSStatus PrintStuff ()
  284. {
  285.     OSStatus    theErr = noErr;
  286.     GrafPtr        oldPort;
  287.     THPrint        thePrRecHdl;
  288.     TPPrPort    thePrPort;
  289.     TPrStatus    theStatus;
  290.  
  291.     GetPort(&oldPort);
  292.     
  293.     thePrRecHdl = (THPrint)  NewHandle (sizeof (TPrint));
  294.     theErr = MemError();
  295.     FAIL_OSERR( theErr, "\pError: Failed to allocate a TPrint record")
  296.     FAIL_NIL (thePrRecHdl, "\pError: Failed to allocate a TPrint record")
  297.     
  298.      PrOpen(); //The PrOpen procedure prepares the current printer driver for use. 
  299.      theErr = PrError();
  300.      FAIL_OSERR (theErr, "\pError: Failed to open the printer driver")
  301.      
  302.     PrintDefault(thePrRecHdl);
  303.     PrValidate(thePrRecHdl);
  304.     theErr = PrError();
  305.      FAIL_OSERR (theErr, "\pError: Failed to create a valid print record")
  306.  
  307.     if (! PrStlDialog(thePrRecHdl)) 
  308.         goto cleanup; // user cancelled
  309.               
  310.     if (! PrJobDialog(thePrRecHdl)) 
  311.         goto cleanup; // user cancelled
  312.  
  313.     thePrPort = PrOpenDoc(thePrRecHdl, nil, nil);
  314.     theErr = PrError();
  315.     
  316.     if (theErr == noErr)
  317.     {
  318.         PrOpenPage(thePrPort, nil);
  319.          theErr = PrError();
  320.          
  321.          if (theErr == noErr)
  322.          {
  323.              // Finally, we're ready to draw!
  324.             DrawStuff ((**thePrRecHdl).prInfo.rPage);
  325.             PrClosePage(thePrPort);
  326.          }
  327.          
  328.          PrCloseDoc(thePrPort);
  329.     }
  330.     
  331.     theErr = PrError();
  332.     FAIL_OSERR (theErr, "\pError: Document failed to print")
  333.     
  334.     if ((((TPPrint)*thePrRecHdl)->prJob.bJDocLoop == bSpoolLoop))
  335.         PrPicFile(thePrRecHdl, nil, nil, nil, &theStatus);                
  336.         
  337.     goto cleanup;
  338.     
  339. error:
  340.     if (theErr == noErr)
  341.         theErr = paramErr;
  342.  
  343.     
  344. cleanup:
  345.     SetPort(oldPort);
  346.     PrClose();
  347.     if (thePrRecHdl)
  348.         DisposeHandle ((Handle) thePrRecHdl);
  349.     
  350.     return theErr;
  351. }  /* PrintStuff */
  352.  
  353. /*------ KillOffscreens  ------------------------------------------------------------------*/
  354. // KillOffscreens cleans up the offscreens.
  355. /*----------------------------------------------------------------------------------------*/
  356.  
  357. OSStatus KillOffscreens()
  358. {
  359.     if (gMaskOffscreen)
  360.         DisposeGWorld(gMaskOffscreen);
  361.     if (gImageOffscreen)
  362.         DisposeGWorld(gImageOffscreen);
  363.     if (gMaskRegion)
  364.         DisposeRgn(gMaskRegion);
  365.  
  366.     return noErr;
  367. } /* KillOffscreens */
  368.  
  369. /*------ DrawStuffToScreen  ------------------------------------------------------------------*/
  370. // DrawStuffToScreen sets up the window port.
  371. // Sets the current port to the window port.
  372. /*----------------------------------------------------------------------------------------*/
  373.  
  374. OSStatus DrawStuffToScreen(void)
  375. {
  376.     WindowRef    theWindow = NULL;
  377.     Rect        bounds = gBoundsRect;
  378.     OSStatus    theErr = noErr;
  379.     GrafPtr        savePort;
  380.     
  381.     GetPort (&savePort);
  382.     
  383.     OffsetRect (&bounds, 30,30);
  384.     theWindow = NewCWindow(NULL, &bounds, "\pFoo", true, 0, (WindowRef)-1, false, 0);
  385.     FAIL_NIL (theWindow, "\pError: Failed to create the window")
  386.  
  387.     SetPortWindowPort (theWindow);
  388.     theErr = DrawStuff(gBoundsRect);
  389.     
  390.     goto cleanup;
  391.     
  392. error:
  393.     if (theErr == noErr)
  394.         theErr = paramErr;
  395.     
  396. cleanup:
  397.     SetPort (savePort);
  398.     
  399.     return theErr;
  400. } /* DrawStuffToScreen */